/**
    ATClab - scriptable Air Traffic Control simulations.
    Copyright (C) 2010 openatclab@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#include "feedback_task.h"

#include <qframe.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qtimer.h>
#include <qpushbutton.h>
#include "atc.h"
#include "presenter.h"
#include "atc_types.h"

using namespace pact;

////////////////////////////////////////////////////////////////////////////////////////////////////
// pact::FeedbackTask
////////////////////////////////////////////////////////////////////////////////////////////////////
FeedbackTask::FeedbackTask(FeedbackTaskBuilder* a_builder) 
  : Task(),
	m_builder(NULL)
{
	m_builder = a_builder;

	if ((a_builder->m_type != FEEDBACK_GENERAL) &&
		(a_builder->m_type != FEEDBACK_NONE))
	{
		DisplayFeedback(m_builder);
		SetConditionalText(m_builder);
	}

	QWidget* widget = (QWidget*)(m_builder->m_widget);
	widget->reparent(this, 0, QPoint());

	QBoxLayout *hmgr = new QHBoxLayout(this);
	hmgr->addWidget(widget);

	connect(m_builder->m_button, SIGNAL(clicked()), this, SLOT(terminate()));	
}

FeedbackTask::~FeedbackTask() 
{
}

void FeedbackTask::showEvent(QShowEvent *e) 
{
	Task::showEvent(e);
	emit sig_shown();
}

void
FeedbackTask::DisplayFeedback(FeedbackTaskBuilder* a_builder)
{
	long displayValue = 0;
	long currentScore = 0;
	long comparisonScore = 0;

	pact::GlobalVariables::iterator it = pact::Presenter::instance()->globals().find("score");
	
	if (it != pact::Presenter::instance()->globals().end())
	{
		currentScore = (*it).second->value();
	}

	switch (a_builder->m_type)
	{
	case FEEDBACK_SELF_REFERENT:
		it = pact::Presenter::instance()->globals().find("previousScore");
		
		if (it != pact::Presenter::instance()->globals().end())
		{
			comparisonScore = (*it).second->value();
		}
		break;
	case FEEDBACK_NORMATIVE:
		std::stringstream normativeScoreRef;

		normativeScoreRef	<< "normScore" 
							<< pact::Presenter::instance()->CurrentTrialTaskNumber();

		it = pact::Presenter::instance()->globals().find(normativeScoreRef.str());

		if (it != pact::Presenter::instance()->globals().end())
		{
			comparisonScore = (*it).second->value();
		}
		break;
	}

	a_builder->m_feedbackValue = comparisonScore - currentScore;

	if (a_builder->m_feedbackValue < 0)
	{
		displayValue = -1 * a_builder->m_feedbackValue;
	}
	else
	{
		displayValue = a_builder->m_feedbackValue;
	}

	it = pact::Presenter::instance()->globals().find(FEEDBACK_VALUE);

	if (it != pact::Presenter::instance()->globals().end())
	{
		it->second->set_value((int) a_builder->m_feedbackValue);
	}

	a_builder->m_feedbackLabel->setText(QString().sprintf("%d", displayValue));
	a_builder->m_feedbackLabel->adjustSize();
}

void
FeedbackTask::SetConditionalText(FeedbackTaskBuilder* a_builder)
{
	std::string conditionText = "";

	for (std::vector<ConditionText>::const_iterator it = a_builder->m_conditionTexts.begin();
			it != a_builder->m_conditionTexts.end(); it++)
	{
		if ((*it).m_condition == "lessThan")
		{
			if (a_builder->m_feedbackValue < (*it).m_value)
			{
				conditionText = (*it).m_text;
			}
		}
		else if ((*it).m_condition == "lessThanOrEqualTo")
		{
			if (a_builder->m_feedbackValue <= (*it).m_value)
			{
				conditionText = (*it).m_text;
			}
		}
		else if ((*it).m_condition == "greaterThan")
		{
			if (a_builder->m_feedbackValue > (*it).m_value)
			{
				conditionText = (*it).m_text;
			}
		}
		else if ((*it).m_condition == "greaterThanOrEqualTo")
		{
			if (a_builder->m_feedbackValue >= (*it).m_value)
			{
				conditionText = (*it).m_text;
			}
		}
	}

	a_builder->m_conditionLabel->setText(QString(conditionText.c_str()));
	a_builder->m_conditionLabel->adjustSize();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// pact::FeedbackTaskBuilder
////////////////////////////////////////////////////////////////////////////////////////////////////
FeedbackTaskBuilder::FeedbackTaskBuilder() 
  : m_widget(new QFrame()),
	m_feedbackLabel(NULL),
	m_conditionLabel(NULL),
	m_feedbackValue(0),
	m_type(FEEDBACK_NONE)
{
	m_font = QFont("Courier New", 12, QFont::Normal);
	m_screenLayout = new QGridLayout(m_widget, 10, 10);
	m_goalTextLayout = new QHBoxLayout(m_widget, 20);
    m_textLayout = new QHBoxLayout(m_widget, 20);

	m_screenLayout->addMultiCellLayout(m_goalTextLayout, 3, 3, 1, 1, Qt::AlignCenter);
	m_screenLayout->addMultiCellLayout(m_textLayout, 5, 5, 1, 1, Qt::AlignCenter);
}

FeedbackTaskBuilder::~FeedbackTaskBuilder()  
{
}

void
FeedbackTaskBuilder::SetText(const std::string& a_text) 
{
	m_text += a_text;

	QLabel* label = new QLabel(a_text.c_str(), m_widget);
	label->setFont(m_font);
	label->setAlignment(Qt::AlignCenter);
	label->adjustSize();
	m_textLayout->addWidget(label);
}

void
FeedbackTaskBuilder::SetGlobalRef(const std::string& a_globalRef)
{
	pact::GlobalVariables::iterator it = 
			pact::Presenter::instance()->globals().find(a_globalRef);
	
	if (it != pact::Presenter::instance()->globals().end())
	{
		std::string value = atc::to_string(it->second->value());
		
		std::string replacementMarker = "%d";
		std::string::size_type found = m_text.find(replacementMarker.c_str());

		if (found != std::string::npos)
		{
			m_text.replace(found, replacementMarker.length(), value);

			// nb: m_text is never re-rendered to screen, so even though it has been updated above those updates will never be displayed.
			// nb: to fix this the following code has been added, which updates the text in the QLabels in the same manner m_text is being updated.

			foreach (QLabel* ql, m_widget->findChildren<QLabel*>()) {
				if (ql->text().find(replacementMarker.c_str())) {
					QString qls = ql->text();
					ql->setText(qls.replace(found, replacementMarker.length(), QString(value.c_str())));
					ql->update();
					break;
				}
			}
		}
	}

}

void
FeedbackTaskBuilder::SetFont(const QFont& a_font)
{
	m_font = a_font;
}

void
FeedbackTaskBuilder::SetGoalText(const std::string& a_text)
{
	QLabel* label = new QLabel(a_text.c_str(), m_widget);

	label->setFont(m_font);
	label->setAlignment(Qt::AlignCenter);
	label->adjustSize();
	m_goalTextLayout->addWidget(label);
}

void
FeedbackTaskBuilder::SetLink(const std::string& a_link)
{
	std::stringstream display;
	std::string msgEnd;

	pact::GlobalVariables::iterator it = pact::Presenter::instance()->globals().find(a_link);

	switch (m_type)
	{
	case FEEDBACK_SELF_REFERENT:
		msgEnd = "your previous performance";
		break;
	case FEEDBACK_NORMATIVE:
		msgEnd = "previous participants";
		break;
	default:
		break;
	}

	if (it != pact::Presenter::instance()->globals().end())
	{
		int goal = (*it).second->value();

		if (goal > 0)
		{
			display << "perform " << goal << " points better than " << msgEnd;
		}
		else if (goal == 0)
		{
			display << "perform neither better nor worse than " << msgEnd;
		}
		else
		{
			display << "avoid performing " << abs(goal) << " points worse than " << msgEnd;
		}

		QLabel* label = new QLabel(display.str().c_str(), m_widget);
		label->setFont(m_font);
		label->setAlignment(Qt::AlignCenter);
		label->adjustSize();
		m_goalTextLayout->addWidget(label);
	}
}

void
FeedbackTaskBuilder::SetFeedback() 
{
	m_feedbackLabel = new QLabel("", m_widget);
	m_feedbackLabel->setFont(m_font);
	m_feedbackLabel->setAlignment(Qt::AlignCenter);
	m_feedbackLabel->adjustSize();
	m_textLayout->addWidget(m_feedbackLabel);
}

void
FeedbackTaskBuilder::SetCondition(const std::string& a_condition,
								  const int a_value,
                                  const std::string& a_text) 
{
	m_conditionLabel = new QLabel("", m_widget);
	m_conditionLabel->setFont(m_font);
	m_conditionLabel->setAlignment(Qt::AlignCenter);
	m_conditionLabel->adjustSize();
	m_textLayout->addWidget(m_conditionLabel);

	ConditionText condition;
	condition.m_condition = a_condition;
	condition.m_value = a_value;
	condition.m_text = a_text;

	m_conditionTexts.push_back(condition);
}

FeedbackTask* 
FeedbackTaskBuilder::build() 
{
	/*QLabel* label = new QLabel(m_text, m_widget);
	label->setFont(m_font);
	label->setAlignment(Qt::AlignCenter);
	label->adjustSize();
	m_textLayout->addWidget(label);*/

	m_button = new QPushButton("OK", m_widget);
	m_button->setGeometry(768, 500, 100, 50);
	m_screenLayout->addWidget(m_button, 7, 1, Qt::AlignCenter);

	return new FeedbackTask(this);
}
